package com.ruoyi.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.ruoyi.api.RemoteAuthService;
import com.ruoyi.api.common.R;
import com.ruoyi.api.domain.EcUser;
import com.ruoyi.api.domain.LDAPLoginDTO;
import com.ruoyi.api.domain.LoginDTO;
import com.ruoyi.domain.*;
import com.ruoyi.dto.*;
import com.ruoyi.platform.constant.Constants;
import org.springframework.util.Assert;
import com.ruoyi.platform.constant.UserConstants;
import com.ruoyi.platform.core.domain.entity.SysDictData;
import com.ruoyi.platform.core.domain.entity.SysUser;
import com.ruoyi.platform.core.domain.model.LoginUser;
import com.ruoyi.platform.exception.ServiceException;
import com.ruoyi.platform.exception.user.UserPasswordNotMatchException;
import com.ruoyi.platform.manager.AsyncManager;
import com.ruoyi.platform.manager.factory.AsyncFactory;
import com.ruoyi.platform.security.context.AuthenticationContextHolder;
import com.ruoyi.platform.system.service.ISysDictDataService;
import com.ruoyi.platform.system.service.ISysUserService;
import com.ruoyi.platform.utils.*;
import com.ruoyi.platform.utils.ip.IpUtils;
import com.ruoyi.platform.web.service.TokenService;
import com.ruoyi.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;


import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;


@Service
@Slf4j
public class FrontServiceImpl implements FrontService {

    @Autowired
    private IBannerService bannerService;

    @Autowired
    private IOnlineShowService onlineShowService;

    @Autowired
    private ISourceCodeUrlService sourceCodeUrlService;

    @Autowired
    private IModuleInfoService moduleInfoService;

    @Autowired
    private IDocumentCategoryService documentCategoryService;

    @Autowired
    private IDocumentService documentService;

    @Autowired
    private IMFileService fileService;

    @Autowired
    private ISpaceDirectoryService spaceDirectoryService;

    @Autowired
    private ISpaceDocumentService spaceDocumentService;

    @Autowired
    private ISpaceRecordService spaceRecordService;

    @Autowired
    private ISpaceCollectionService spaceCollectionService;

    @Autowired
    private ISysUserService sysUserService;

    @Autowired
    private ISysDictDataService dictDataService;

    @Autowired
    private TokenService tokenService;

    @Resource
    private AuthenticationManager authenticationManager;

    @Autowired
    private RemoteAuthService remoteAuthService;

    /**
     * 前台用户登陆
     *
     * @param loginDTO
     * @return
     */
    @Override
    public String doLogin(FrontUserLoginDto loginDTO) {
        //1.调用auth的login接口返回ticket信息
        LDAPLoginDTO dto = new LDAPLoginDTO();
        dto.setUserAccount(loginDTO.getJobNo());
        dto.setPassWord(loginDTO.getPassword());
        String ticket = remoteAuthService.ldapLogin(dto).getData();
        Assert.hasText(ticket, "LDAP登录失败");
        //2.根据ticket调用获取用户信息的方法
        LoginDTO res= remoteAuthService.getUserInfoByTicket(ticket).getData();
//        //json字符串转成对象
//        MgDTO mgDTO = JSON.parseObject(jsonStr, MgDTO.class);
        //3.子系统的用户验证
        String userAccount = res.getUserAccount();
        String password = Constants.LDAP_DEFAULT_PASSWORD;
        Authentication authentication;
        try {
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userAccount, password);
            AuthenticationContextHolder.setContext(authenticationToken);
            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
            authentication = authenticationManager.authenticate(authenticationToken);
        } catch (Exception e) {
            if (e instanceof BadCredentialsException) {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(userAccount, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
                throw new UserPasswordNotMatchException();
            } else {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(userAccount, Constants.LOGIN_FAIL, e.getMessage()));
                throw new ServiceException(e.getMessage());
            }
        } finally {
            AuthenticationContextHolder.clearContext();
        }
        AsyncManager.me().execute(AsyncFactory.recordLogininfor(userAccount, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        recordLoginInfo(loginUser.getUserId());
        // 生成token
        return tokenService.createToken(loginUser);
    }

    /**
     * 记录登录信息
     *
     * @param userId 用户ID
     */
    public void recordLoginInfo(Long userId) {
        SysUser sysUser = new SysUser();
        sysUser.setUserId(userId);
        sysUser.setLoginIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
        sysUser.setLoginDate(DateUtils.getNowDate());
        sysUserService.updateUserProfile(sysUser);
    }

    /**
     * 前台-查询可展示轮播图
     *
     * @return
     */
    @Override
    public List<Banner> selectBannerList(Integer type) {
        LambdaQueryWrapper<Banner> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(Banner::getIsShow, 1L);
        queryWrapper.eq(Banner::getType, type);
        return bannerService.list(queryWrapper);
    }

    /**
     * 前台-查询在线演示
     *
     * @return
     */
    @Override
    public List<OnlineShow> onlineShowList() {
        return onlineShowService.selectOnlineShowList(new OnlineShow());
    }

    @Override
    public List<SourceCodeUrl> sourceCodeList() {
        return sourceCodeUrlService.selectSourceCodeUrlList(new SourceCodeUrl());
    }

    @Override
    public List<ModuleInfo> extendComponentList(String type) {
        List<ModuleInfo> parentList = moduleInfoService.selectParentModuleInfo(Long.valueOf(type));
        for (ModuleInfo moduleInfo : parentList) {
            List<ModuleInfo> childrenList = moduleInfoService.selectChildrenModuleInfo(moduleInfo.getId());
            moduleInfo.setChildren(childrenList);
        }
        return parentList;
    }

    /**
     * 前台-加载在线文档目录树
     *
     * @return
     */
    @Override
    public List<CategoryTree> documentTreeData(Long type) {
        DocumentCategory documentCategory = new DocumentCategory();
        documentCategory.setCategoryType(type.intValue());
        return documentCategoryService.getTreeList(documentCategory);
    }

    /**
     * 前台-查询文档地址
     *
     * @param id
     * @return
     */
    @Override
    public String selectFileUrl(Integer id) {
        String result = "";
        Document document = documentService.selectDocumentById(id);
        if (BeanUtils.isNotEmpty(document)) {
            MFile file = fileService.selectMFileById(document.getFileId());
            result = file.getFileUrl();
        }
        return result;
    }

    /**
     * 前台-在线文档默认显示第一个文档
     *
     * @return
     */
    @Override
    public Long selectFirstFile() {
        DocumentCategory documentCategory = documentCategoryService.selectFirstFile();
        if (BeanUtils.isNotEmpty(documentCategory)) {
            return documentCategory.getDocumentId();
        }
        return 0L;
    }

    @Override
    public Long selectDocIdByModuleName(String moduleName) {
        return documentService.lambdaQuery().like(Document::getName, moduleName).list().get(0).getId().longValue();
    }

    /**
     * 前台-智联空间目录树
     *
     * @return
     */
    @Override
    public List<SpaceDirectoryTree> getSpaceDirectoryTree() {
        return spaceDirectoryService.getTreeList(new SpaceDirectory());
    }

    @Override
    public List<SpaceDirectory> getDirectorySelectTree() {
        return spaceDirectoryService.getDirectorySelectTree(new SpaceDirectory());
    }

    @Override
    public List<SpaceDirectory> getIndexSpaceDirectoryTree(Long userId, String type) {
        SpaceDirectory spaceDirectory = new SpaceDirectory();
        if (StringUtils.isNotEmpty(type)) {
            spaceDirectory.setType(Long.valueOf(type));
        }
        return spaceDirectoryService.getIndexTreeList(spaceDirectory, userId);
    }

    @Transactional
    @Override
    public String getSpaceDocUrl(Long spaceFileId) {
        String result = "";
        SpaceDocument spaceDocument = spaceDocumentService.getById(spaceFileId);
        SpaceRecord spaceRecord = new SpaceRecord();
        spaceRecord.setType(3L);
        spaceRecord.setDocumentId(spaceDocument.getId());
        spaceRecordService.insertSpaceRecord(spaceRecord);
        if (BeanUtils.isNotEmpty(spaceDocument)) {
            MFile file = fileService.selectMFileById(spaceDocument.getFileId());
            result = file.getFileUrl();
        }
        return result;
    }

    @Override
    public int addSpaceDirectory(SpaceDirectory spaceDirectory) {
        Assert.isTrue(!UserConstants.NOT_UNIQUE.equals(spaceDirectoryService.checkDirectoryNameUnique(spaceDirectory)), "失败，文件夹已存在");
        return spaceDirectoryService.insertSpaceDirectory(spaceDirectory);
    }

    @Override
    @Transactional
    public int addSpaceDocument(List<SpaceDocument> spaceDocument) {
        return spaceDocumentService.insertSpaceDocument(spaceDocument);
    }

    @Override
    public int addCollection(Long documentId) {
        SpaceCollection spaceCollection = new SpaceCollection();
        spaceCollection.setDocumentId(documentId);
        spaceCollection.setDelFlag(0L);
        spaceCollection.setCreateBy(String.valueOf(SecurityUtils.getUserId()));
        return spaceCollectionService.insertSpaceCollection(spaceCollection);
    }

    @Override
    @Transactional
    public int removeSpaceDocument(Long id) {
        spaceDirectoryService.remove(new LambdaQueryWrapper<SpaceDirectory>().eq(SpaceDirectory::getDocumentId, id));
        return spaceDocumentService.deleteSpaceDocumentById(id);
    }

    @Override
    public int removeSpaceDirectory(Long id) {
        return spaceDirectoryService.deleteSpaceDirectoryById(id);
    }

    @Override
    public DocumentFile upload(MultipartFile file) {
        RepFile repFile = new RepFile();
        DocumentFile documentFile = new DocumentFile();
        try {
            repFile = fileService.uploadFile(file, "2");
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        documentFile.setFileUrl(repFile.getFileUrl());
        documentFile.setFileId(repFile.getFileId());
        documentFile.setOriginFileName(repFile.getOriginFileName());
        String[] nameSplit = repFile.getOriginFileName().split("\\.");
        String fileSuffix = nameSplit[nameSplit.length - 1];
        documentFile.setSuffix(fileSuffix);
        List<SysDictData> sysDictData = dictDataService.selectDictDataByLabel(fileSuffix);
        String fileTypeName;
        if (sysDictData.size() != 0) {
            fileTypeName = dictDataService.selectDictLabel("document_type", sysDictData.get(0).getDictValue());
            documentFile.setFileTypeName(fileTypeName);
            documentFile.setFileTypeId(sysDictData.get(0).getDictValue());
        } else {
            documentFile.setFileTypeName("其他文件");
            documentFile.setFileTypeId("7");
        }
        return documentFile;
    }

    @Override
    public void updateSpaceDirectory(SpaceDirectory spaceDirectory) {
        SpaceDirectory directory = spaceDirectoryService.selectSpaceDirectoryById(spaceDirectory.getId());
        if (StringUtils.isNotNull(directory.getDocumentId())) {
            SpaceDocument spaceDocument = spaceDocumentService.selectSpaceDocumentById(directory.getDocumentId());
            spaceDocument.setName(spaceDirectory.getName());
            spaceDocumentService.updateSpaceDocument(spaceDocument);
        }
        spaceDirectoryService.update(spaceDirectory);
    }

    @Override
    @Transactional
    public void download(HttpServletRequest req, HttpServletResponse res, Long spaceDocId) {
        SpaceRecord spaceRecord = new SpaceRecord();
        spaceRecord.setType(2L);
        spaceRecord.setCreateBy(String.valueOf(SecurityUtils.getUserId()));
        spaceRecord.setDocumentId(spaceDocId);
        spaceRecordService.insertSpaceRecord(spaceRecord);
        fileService.downloadFileBySpaceDocId(res, req, spaceDocId);
    }

    @Override
    public List<Map<String, Object>> getSpaceDocumentStatInfo() {
        return spaceDocumentService.getDocTypeStatInfo();
    }

    @Override
    public List<DynamicRecord> getSpaceDynamicRecord(Integer page) {
        return spaceRecordService.selectDynamicRecord(page);
    }

    /**
     * 模糊查询智联文档或目录
     *
     * @param searchItem
     * @return
     */
    @Override
    public List<SpaceDirectory> fuzzySearchSpaceDoc(String searchItem, Long type) {
        if (type != null) {
            return spaceDirectoryService.lambdaQuery().eq(SpaceDirectory::getType, type).like(SpaceDirectory::getName, searchItem).list();
        }
        return spaceDirectoryService.lambdaQuery().like(SpaceDirectory::getName, searchItem).list();
    }

    @Override
    public List<SpaceRecord> getOperateCountRank(Long type, String timeSpan, LocalDate startTime, LocalDate endTime, Integer currentPage) {
        return spaceRecordService.getOperateCountRank(type, timeSpan, startTime, endTime, currentPage);
    }

    @Override
    public List<SpaceRecord> getUploadRank(Long type, String timeSpan, LocalDate startTime, LocalDate endTime) {
        return spaceRecordService.getUploadRank(type, timeSpan, startTime, endTime);
    }

    @Override
    public SpaceDocumentDetail getSpaceDocumentDetail(Long documentId) {
        return spaceRecordService.getDocStatInfoByDocumentId(documentId);
    }

    @Override
    public List<PersonalDocInfo> getRecordByUserId(String userId, String recordType, String documentName, Integer page) {
        return spaceRecordService.getRecordByUserId(userId, recordType, documentName, page);
    }

    @Override
    public List<SpaceCollection> getCollectByUserId(String userId, String documentName, Integer page) {
        return spaceCollectionService.getCollectByUserId(userId, documentName, page);
    }

    @Override
    public Integer getPersonCount() {
        return sysUserService.selectUserList(new SysUser()).size();
    }

    @Override
    public List<SysDictData> selectDocumentType(String dictType) {
        SysDictData dict = new SysDictData();
        dict.setDictType(dictType);
        return dictDataService.selectDictDataList(dict);
    }

    @Override
    public List<SysDictData> selectDirectoryType() {
        SysDictData dictData = new SysDictData();
        dictData.setDictType("directory_type");
        return dictDataService.selectDictDataList(dictData);
    }

    @Override
    public SpaceDirectory selectDirectoryById(Long id) {
        return spaceDirectoryService.selectSpaceDirectoryById(id);
    }

    @Override
    public int removeCollection(Long documentId) {
        SpaceCollection spaceCollection = new SpaceCollection();
        spaceCollection.setDocumentId(documentId);
        spaceCollection.setCreateBy(String.valueOf(SecurityUtils.getUserId()));
        return spaceCollectionService.removeByDocumentIdAndCreateBy(spaceCollection);
    }

    @Override
    public void moveDirectory(Long id, Long parentId, Long type) {
        //通过id获取文件对象
        SpaceDirectory directory = spaceDirectoryService.selectSpaceDirectoryById(id);
        SpaceDirectory parentDirectory = spaceDirectoryService.selectSpaceDirectoryById(parentId);

        directory.setParentId(parentId);
        directory.setType(type);
        if (parentId == 0) {
            directory.setAncestors("0");
        } else {
            directory.setAncestors(parentDirectory.getAncestors() + "," + parentId);
        }
        //如果有document_id，说明是单个文档，只需要移动文档就行
        spaceDirectoryService.update(directory);

        if (StringUtils.isNull(directory.getDocumentId())) {

            //如果没有document_id，说明是个文件，需要查出文件下的所有文档，更改完文件的parent_id、ancestors，需要再更改文档的ancestors
            //首先查出子对象
            List<SpaceDirectory> list = spaceDirectoryService.selectSpaceDirectoryByParentId(id);
            //便利list集合修改
            for (SpaceDirectory spaceDirectory : list) {
                spaceDirectory.setType(type);
                spaceDirectory.setAncestors(directory.getAncestors() + "," + directory.getId());
                spaceDirectoryService.update(spaceDirectory);
            }
        }


    }


    @Override
    public List<SpaceDirectory> getParentDirectoryNode(Long docId, Long directoryId) {
        List<SpaceDirectory> res = new ArrayList<>();
        if (docId != null) {
            SpaceDirectory spaceDirectory = spaceDirectoryService.getOne(new LambdaQueryWrapper<SpaceDirectory>().eq(SpaceDirectory::getDocumentId, docId));
            String[] nodes = spaceDirectory.getAncestors().split(",");
            for (int i = 1; i < nodes.length; i++) {
                res.add(spaceDirectoryService.getOne(new LambdaQueryWrapper<SpaceDirectory>().eq(SpaceDirectory::getId, nodes[i])));

            }
            return res;
        }
        SpaceDirectory spaceDirectory = spaceDirectoryService.getOne(new LambdaQueryWrapper<SpaceDirectory>().eq(SpaceDirectory::getId, directoryId));
        String[] nodes = spaceDirectory.getAncestors().split(",");
        if (nodes.length == 1 && "0".equals(nodes[0])) {
            res.add(spaceDirectory);
            return res;
        }
        for (int i = 1; i < nodes.length; i++) {
            res.add(spaceDirectoryService.getOne(new LambdaQueryWrapper<SpaceDirectory>().eq(SpaceDirectory::getId, nodes[i])));
        }
        return res;

    }

    @Override
    public List<SpaceDirectory> getFirstIndexSpaceDirectoryTree(Long userId, Long type) {
        return spaceDirectoryService.selectFirstIndexTree(type);
    }

    @Override
    public Integer getTotal(String userId, String recordType, String documentName) {
        return spaceRecordService.getTotal(userId, recordType, documentName);
    }

    @Override
    public Integer getCollectTotal(String userId, String documentName) {
        return spaceCollectionService.getCollectionTotal(userId, documentName);
    }

    @Override
    public Long getDirectoryFirstDocId(Long directoryId) {
        List<SpaceDirectory> spaceDirectories = spaceDirectoryService.list(new LambdaQueryWrapper<SpaceDirectory>().eq(SpaceDirectory::getParentId, directoryId));
        if (spaceDirectories.size() != 0) {
            for (SpaceDirectory spaceDirectory : spaceDirectories) {
                if (spaceDirectory.getDocumentId() != null) {
                    return spaceDirectory.getDocumentId();
                }
            }
            List<SpaceDirectory> spaceDirectoryList = spaceDirectoryService.list(new LambdaQueryWrapper<SpaceDirectory>().eq(SpaceDirectory::getParentId, spaceDirectories.get(0).getId()));
            for (SpaceDirectory spaceDirectory : spaceDirectoryList) {
                if (spaceDirectory.getDocumentId() != null) {
                    return spaceDirectory.getDocumentId();
                }
            }
        }
        return null;
    }

    @Override
    public List<SysDictData> getFileTypeWithSuffix(String type) {
        SysDictData sysDictData = new SysDictData();
        sysDictData.setDictType("document_file_type");
        sysDictData.setDictValue(type);
        return dictDataService.selectDictDataList(sysDictData);
    }

    @Override
    public List<SpaceDocumentDetail> getImagesUnderDirectory(Long docId) {
        return spaceDocumentService.selectImagesUnderDirectory(docId);
    }

    @Override
    public Integer selectAllDynamicRecordCount() {
        return spaceRecordService.getTotal(null, null, null);
    }

}
